package com.perceptivesoftware.licensing.client.dialogs.useradmin;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
import com.extjs.gxt.ui.client.Style.LayoutRegion;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.ModelStringProvider;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.KeyListener;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.MenuEvent;
import com.extjs.gxt.ui.client.event.MessageBoxEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.event.TreePanelEvent;
import com.extjs.gxt.ui.client.store.TreeStore;
import com.extjs.gxt.ui.client.util.Margins;
import com.extjs.gxt.ui.client.widget.Dialog;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.layout.BorderLayout;
import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.menu.Menu;
import com.extjs.gxt.ui.client.widget.menu.MenuItem;
import com.extjs.gxt.ui.client.widget.treepanel.TreePanel;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.perceptivesoftware.licensing.client.LicensingRPCFactory;
import com.perceptivesoftware.licensing.client.PerceptiveUISession;
import com.perceptivesoftware.licensing.client.common.DirtyCallbackHandler;
import com.perceptivesoftware.licensing.client.common.util.ClientConstants;
import com.perceptivesoftware.licensing.client.common.util.ClientUtils;
import com.perceptivesoftware.licensing.client.common.util.PerceptiveLicensingMessageBox;
import com.perceptivesoftware.licensing.client.common.util.Utils;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.callbackhandlers.ActionCompleteHandler;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.callbackhandlers.AddCallbackHandler;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.callbackhandlers.DeleteCallbackHandler;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.callbackhandlers.ItemSelectedCallbackHandler;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.callbackhandlers.RenameCallbackHandler;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.callbackhandlers.SaveCallbackHandler;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.callbackhandlers.SaveDiscardButtonCallbackHandler;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.callbackhandlers.SecurityManagerAsyncCallback;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.interfaces.Addable;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.interfaces.CustomAdminActionItem;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.interfaces.CustomAdminActionItemable;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.interfaces.CustomNavItemRenderer;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.interfaces.Deletable;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.interfaces.Parent;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.interfaces.Renamable;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.interfaces.Saveable;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.plugin.SecurityManagerNavItem;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.plugin.SecurityManagerPlugin;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.plugin.eh.EHNavItem;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.plugin.eh.EHPlugin;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.plugin.role.RoleNavItem;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.plugin.role.RolePlugin;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.plugin.superadmin.SuperAdminRootNavItem;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.plugin.superadmin.SuperAdminRootPlugin;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.plugin.user.UserNavItem;
import com.perceptivesoftware.licensing.client.dialogs.useradmin.plugin.user.UserPlugin;
import com.perceptivesoftware.licensing.client.dto.SecurityTreeDTO;

public class UserAdminstrationDialog extends Dialog {

	private final SecurityManagerTreePanel securityManagerTreePanel;
	private final MainSecurityManagerPanel mainSecurityManagerPanel;
	private final TreeStore<SecurityManagerNavModel> treeStore = new TreeStore<SecurityManagerNavModel>();
	// PerceptiveUISession nts = PerceptiveUISession.getInstance();

	// private SecurityManagerPlugin currentlySelectedPlugin;
	private SecurityManagerNavModel currentlySelectedModel;
	private Boolean squelchSelectionChangeListener = false;
	private final HashMap<Class<?>, SecurityManagerPlugin<?>> itemClassToPlugin = new HashMap<Class<?>, SecurityManagerPlugin<?>>();
	private MessageBox progress;
	private int progressDepth = 0;
	private boolean currentPluginIsDirty = false;

	public UserAdminstrationDialog() {
		setHeading("User Administration");
		securityManagerTreePanel = new SecurityManagerTreePanel(treeStore);
		mainSecurityManagerPanel = new MainSecurityManagerPanel(new SaveDiscardButtonCallbackHandler() {

			@Override
			public void discardButtonClicked() {
				theDiscardButtonClicked();
			}

			@Override
			public void saveButtonClicked() {
				theSaveButtonClicked();
			}
		});

		getSecurityManagerTree().setContextMenu(null);
		getSecurityManagerTree().addListener(Events.OnMouseDown, new Listener<TreePanelEvent<SecurityManagerNavModel>>() {

			@Override
			public void handleEvent(@SuppressWarnings("unused") final TreePanelEvent<SecurityManagerNavModel> tpe) {
				if (getSecurityManagerTree().getSelectionModel().getSelectedItems().size() > 0) {
					// used to re-load the context menu in the case that
					// it was
					// clicked before. Fixes red context menu item
					// issue.
					setupContextMenu();
				}
			}
		});
		getSecurityManagerTree().getSelectionModel().addListener(Events.SelectionChange, new Listener<SelectionChangedEvent<SecurityManagerNavModel>>() {

			@Override
			public void handleEvent(@SuppressWarnings("unused") final SelectionChangedEvent<SecurityManagerNavModel> sce) {
				handleTreeSelectionChangeEvent();
			}
		});
		getSecurityManagerTree().addListener(Events.Expand, new Listener<TreePanelEvent<SecurityManagerNavModel>>() {

			@Override
			public void handleEvent(final TreePanelEvent<SecurityManagerNavModel> tpe) {
				final SecurityManagerNavModel SecurityManagerNavModel = tpe.getItem();
				final List<SecurityManagerNavModel> children = treeStore.getChildren(SecurityManagerNavModel);
				for (final ModelData child : children) {
					deferCheckForChildren((SecurityManagerNavModel) child);
				}
			}
		});
		getSecurityManagerTree().setLabelProvider(new ModelStringProvider<SecurityManagerNavModel>() {

			@Override
			public String getStringValue(final SecurityManagerNavModel model, @SuppressWarnings("unused") final String property) {
				final SecurityManagerPlugin<?> plugin = model.getSecurityManagerPlugin();
				if (plugin instanceof CustomNavItemRenderer) {
					final CustomNavItemRenderer cnir = (CustomNavItemRenderer) plugin;
					final StringBuffer sb = new StringBuffer();
					sb.append("<span style='");
					sb.append(cnir.getCustomNavItemRenderStyle(model.getSecurityManagerNavItem()));
					sb.append("'");
					if (model.getSecurityManagerNavItem().getToolTip() != null) {
						sb.append(" title='");
						sb.append(model.getSecurityManagerNavItem().getToolTip());
						sb.append("'");
					}
					sb.append(">");
					sb.append(cnir.getCustomNavItemRenderText(model.getSecurityManagerNavItem()));
					sb.append("</span>");
					return sb.toString();
				}
				if (model.getSecurityManagerNavItem().getToolTip() == null) {
					return model.getName();
				}
				return "<span title='" + model.getSecurityManagerNavItem().getToolTip() + "'>" + model.getName() + "</span>";
			}
		});
		// v.layout();
		clearMainPanel();
		loadInitialData();
		setSize(800, 600);
		setButtonAlign(HorizontalAlignment.CENTER);
		setButtons(Dialog.CLOSE);
		setHideOnButtonClick(true);
	}

	private void deferCheckForChildren(final SecurityManagerNavModel smnm) {
		DeferredCommand.addCommand(new Command() {

			public void execute() {
				checkForChildren(smnm);
			}
		});
	}

	private void theSaveButtonClicked() {
		showProcessingScreen();
		if (!(currentlySelectedModel.getSecurityManagerPlugin() instanceof Saveable)) {
			return;
		}
		((Saveable) currentlySelectedModel.getSecurityManagerPlugin()).save(new SaveCallbackHandler() {

			@Override
			public void saveFailed() {
				removeProcessingScreen();
			}

			@Override
			public void saved() {
				pluginNotDirty();
				removeProcessingScreen();
			}
		});
	}

	private void theDiscardButtonClicked() {
		actuallyHandleSelectionChange();
	}

	private void loadInitialData() {
		final String roleValCode = ClientUtils.getRoleCodeFromCookieAndClearIt();
		final MessageBox wait = MessageBox.wait("Loading", "Loading Initial Admin Data", "Loading...");
		LicensingRPCFactory.getSecurityService(true).getSecurityTreeDTO(roleValCode, new SecurityManagerAsyncCallback<SecurityTreeDTO>() {

			@Override
			public void onSuccess(final SecurityTreeDTO securityTreeDTO) {
				PerceptiveUISession.getInstance().setSecurityTreeDTO(securityTreeDTO);
				loadInitialModels(treeStore, securityTreeDTO);
				wait.close();
				removeAll();
				final LayoutContainer mainContainer = new LayoutContainer();
				final BorderLayout bl = new BorderLayout();
				mainContainer.setLayout(bl);
				final BorderLayoutData adminTreeBLD = new BorderLayoutData(LayoutRegion.WEST, 250);
				adminTreeBLD.setSplit(true);
				adminTreeBLD.setCollapsible(true);
				adminTreeBLD.setMargins(new Margins(5, 5, 5, 5));
				final BorderLayoutData mainPanelBLD = new BorderLayoutData(LayoutRegion.CENTER);
				mainPanelBLD.setMargins(new Margins(5, 5, 5, 0));
				mainContainer.add(securityManagerTreePanel, adminTreeBLD);
				mainContainer.add(mainSecurityManagerPanel, mainPanelBLD);
				setLayout(new FitLayout());
				add(mainContainer);
				setLayoutOnChange(true);
				setMonitorWindowResize(true);
				addListener(Events.Resize, new Listener<BaseEvent>() {

					@Override
					public void handleEvent(@SuppressWarnings("unused") final BaseEvent be) {
						// securityManagerTreePanel.layout();
						layout();
					}

				});
				layout(true);
			}

			@Override
			public void onPerceptiveFailure(final Throwable caught) {
				MessageBox.alert("Data Retrieval", caught.getMessage(), new Listener<MessageBoxEvent>() {

					@Override
					public void handleEvent(@SuppressWarnings("unused") final MessageBoxEvent be) {
						Utils.redirectToUrl(ClientConstants.USER_LOGIN_URL);
					}
				});
			}
		});
	}

	private void loadInitialModels(final TreeStore<SecurityManagerNavModel> store, final SecurityTreeDTO navItems) {

		final EHNavItem ehNavItem = new EHNavItem();
		final SecurityManagerNavModel rootNavModel = addRootNavModel(ehNavItem);
		deferCheckForChildren(rootNavModel);
		// for (final OrgNavItem org : navItems.getOrgs())
		// {
		// final SecurityManagerNavModel rootNavModel = addRootNavModel(org);
		// deferCheckForChildren(rootNavModel);
		// }
	}

	private SecurityManagerNavModel addRootNavModel(final SecurityManagerNavItem smni) {
		final SecurityManagerPlugin<?> pluginForItem = getPluginForItem(smni);
		final SecurityManagerNavModel SecurityManagerNavModel = new SecurityManagerNavModel(smni, pluginForItem);
		treeStore.add(SecurityManagerNavModel, false);
		return SecurityManagerNavModel;
	}

	private void addNavModelToParent(final SecurityManagerNavItem smni, final SecurityManagerNavModel parent) {
		final SecurityManagerPlugin<?> pluginForItem = getPluginForItem(smni);
		final SecurityManagerNavModel SecurityManagerNavModel = new SecurityManagerNavModel(smni, pluginForItem);
		treeStore.add(parent, SecurityManagerNavModel, false);
		checkForChildren(SecurityManagerNavModel);
		getSecurityManagerTree().setExpanded(parent, true);
	}

	private void checkForChildren(final SecurityManagerNavModel smnm) {
		if (treeStore.getChildCount(smnm) > 0) {
			return;
		}
		final SecurityManagerNavItem securityManagerNavItem = smnm.getSecurityManagerNavItem();
		final SecurityManagerPlugin<?> plugin = getPluginForItem(securityManagerNavItem);
		if (plugin instanceof Parent) {
			final Parent chci = (Parent) plugin;
			final List<SecurityManagerNavItem> children = chci.getChildren(securityManagerNavItem);
			final List<SecurityManagerNavModel> toAdd = new ArrayList<SecurityManagerNavModel>();
			for (final SecurityManagerNavItem smnichild : children) {
				final SecurityManagerNavModel childSecurityManagerNavModel = new SecurityManagerNavModel(smnichild, getPluginForItem(smnichild));
				toAdd.add(childSecurityManagerNavModel);
			}
			treeStore.add(smnm, toAdd, true);
		}
		securityManagerTreePanel.getTreePanel().expandAll();
	}

	private void showProcessingScreen() {
		if (progressDepth == 0) {
			progress = MessageBox.wait("", "", "Processing");
		}
		progressDepth++;
	}

	private void removeProcessingScreen() {
		progressDepth--;
		if (progressDepth == 0) {
			progress.close();
		}
	}

	private SecurityManagerPlugin<?> getPluginForItem(final SecurityManagerNavItem smni) {
		SecurityManagerPlugin<?> smp = itemClassToPlugin.get(smni.getClass());
		if (smp == null) {
			if (smni instanceof EHNavItem) {
				smp = new EHPlugin();
			}
			else if (smni instanceof RoleNavItem) {
				smp = new RolePlugin();
			}
			else if (smni instanceof UserNavItem) {
				smp = new UserPlugin();
			}
			else if (smni instanceof SuperAdminRootNavItem) {
				smp = new SuperAdminRootPlugin();
			}
			else {
				throw new RuntimeException("PluginFactory does not know how to handle a " + smni.getClass().getName());
			}
			smp.initSecurityManagerPluginCallback(createSecurityManagerPluginCallback());
			if (smp instanceof Saveable) {
				((Saveable) smp).dirtyCallbackHandler(new DirtyCallbackHandler() {

					@Override
					public void iAmDirty() {
						currentPluginDirty();
					}
				});
			}
			smp.init();
			itemClassToPlugin.put(smni.getClass(), smp);
		}
		return smp;
	}

	private SecurityManagerPluginCallback createSecurityManagerPluginCallback() {
		return new SecurityManagerPluginCallback() {

			@Override
			public void refreshActionItems() {
				setupContextMenu();
			}

			@Override
			public void updateNavItemsChildren(final SecurityManagerNavItem smni) {
				final SecurityManagerNavModel smnm = getModelForItem(smni);
				while (treeStore.getChildren(smnm).size() > 0) {
					treeStore.remove(treeStore.getChildren(smnm).get(0));
				}
				checkForChildren(smnm);
				getSecurityManagerTree().setExpanded(smnm, true);
			}

			@Override
			public void updateNavItem(final SecurityManagerNavItem smni) {
				try {
					final SecurityManagerNavModel navModel = getModelForItem(smni);
					if (navModel != null) {
						treeStore.update(getModelForItem(smni));
					}
				}
				catch (final ModelNotFoundException e) {/* should not happen */
				}
			}

			@Override
			public void deleteNavItemFromTree(final SecurityManagerNavItem smni) {
				treeStore.remove(getModelForItem(smni));
			}

			@Override
			public void addNavItem(final SecurityManagerNavItem parent, final SecurityManagerNavItem child) {
				addNavModelToParent(child, getModelForItem(parent));
			}
		};
	}

	private void currentPluginDirty() {
		currentPluginIsDirty = true;
		mainSecurityManagerPanel.enableSaveDiscardButtons();
	}

	private void pluginNotDirty() {
		currentPluginIsDirty = false;
		mainSecurityManagerPanel.disableSaveDiscardButtons();
	}

	private void clearMainPanel() {
		mainSecurityManagerPanel.setBreadcrumbs(null, null);
		mainSecurityManagerPanel.setCurrentComposite(null, false);
	}

	private TreePanel<SecurityManagerNavModel> getSecurityManagerTree() {
		return securityManagerTreePanel.getTreePanel();
	}

	private void handleTreeSelectionChangeEvent() {
		if (squelchSelectionChangeListener) {
			return;
		}
		final SecurityManagerNavModel _currentlySelectedModel = currentlySelectedModel;
		if (_currentlySelectedModel != null && currentPluginIsDirty) {
			ClientUtils.yesNoCancelMessageBox("Unsaved Changes", "You have unsaved changes; save now?", new Listener<MessageBoxEvent>() {

				@Override
				public void handleEvent(final MessageBoxEvent be) {
					if (be.getButtonClicked().getItemId().equals(Dialog.YES)) {
						((Saveable) _currentlySelectedModel.getSecurityManagerPlugin()).save(new SaveCallbackHandler() {

							@Override
							public void saveFailed() {
								changeSelectionSilently(_currentlySelectedModel);
							}

							@Override
							public void saved() {
								actuallyHandleSelectionChange();
							}
						});
					}
					else if (be.getButtonClicked().getItemId().equals(Dialog.NO)) {
						actuallyHandleSelectionChange();
					}
					else {
						changeSelectionSilently(_currentlySelectedModel);
					}
				}
			});
		}
		else {
			actuallyHandleSelectionChange();
		}
	}

	private void changeSelectionSilently(final SecurityManagerNavModel selectedModel) {
		final boolean previousSquelchValue = squelchSelectionChangeListener;
		squelchSelectionChangeListener = true;
		if (selectedModel == null) {
			clearMainPanel();
			getSecurityManagerTree().setContextMenu(null);
		}
		else {
			final ArrayList<SecurityManagerNavModel> al = new ArrayList<SecurityManagerNavModel>();
			al.add(selectedModel);
			getSecurityManagerTree().getSelectionModel().setSelection(al);
			mainSecurityManagerPanel.setBreadcrumbs(selectedModel, treeStore);
			setupContextMenu();
		}
		squelchSelectionChangeListener = previousSquelchValue;
	}

	private void setupContextMenu() {
		final SecurityManagerNavItem smni = currentlySelectedModel.getSecurityManagerNavItem();
		final SecurityManagerNavModel smnm = currentlySelectedModel;
		final Menu contextMenu = new Menu();
		final SecurityManagerPlugin<? extends SecurityManagerNavItem> plugin = currentlySelectedModel.getSecurityManagerPlugin();
		if (plugin instanceof Renamable && ((Renamable) plugin).canRename(smni)) {
			final Renamable renamable = (Renamable) plugin;
			final MenuItem mi = new MenuItem("Rename " + smni.getName());
			mi.setIconStyle(renamable.getRenameIconStyle());
			mi.addListener(Events.Select, new Listener<MenuEvent>() {

				@Override
				public void handleEvent(@SuppressWarnings("unused") final MenuEvent me) {
					showProcessingScreen();
					// final MessageBox prompt = MessageBox.prompt("Rename",
					// "Enter a new name for '" + smni.getName() + "'", new
					// Listener<MessageBoxEvent>(){
					final MessageBox prompt = PerceptiveLicensingMessageBox.prompt("Rename " + renamable.getRenameName(), "New " + renamable.getRenameName()
							+ " name:", new Listener<MessageBoxEvent>() {

						@Override
						public void handleEvent(final MessageBoxEvent be) {
							if (be.getButtonClicked().getItemId().equals(Dialog.OK)) {
								renamable.rename(be.getValue().trim(), smni, new RenameCallbackHandler() {

									@Override
									public void renameFailed(final String renameFailureReason) {
										MessageBox.alert("Rename Failed", renameFailureReason, null);
										removeProcessingScreen();
									}

									@Override
									public void renamed(final String newName) {
										smnm.getSecurityManagerNavItem().setName(newName);
										smnm.set("name", newName);
										treeStore.update(smnm);
										mainSecurityManagerPanel.setBreadcrumbs(currentlySelectedModel, treeStore);
										removeProcessingScreen();
									}
								});
							}
							else {
								removeProcessingScreen();
							}
						}
					});
					prompt.getTextBox().setValue(smni.getName());
					prompt.getTextBox().setSelectionRange(0, smni.getName().length());
					prompt.getTextBox().addKeyListener(new KeyListener() {

						@Override
						public void componentKeyUp(final ComponentEvent event) {
							if (ClientConstants.EXTJS_KEY_VALUE_ENTER == event.getKeyCode()) {
								prompt.getDialog().getButtonBar().getItem(0).fireEvent(Events.Select);
							}
						}
					});

				}
			});
			contextMenu.add(mi);
		}
		if (plugin instanceof Deletable && ((Deletable) plugin).canDelete(smni)) {
			final Deletable deletable = (Deletable) plugin;
			final MenuItem mi = new MenuItem("Delete " + smni.getName());
			mi.setIconStyle(deletable.getDeleteIconStyle());
			mi.addListener(Events.Select, new Listener<MenuEvent>() {

				@Override
				public void handleEvent(@SuppressWarnings("unused") final MenuEvent me) {
					MessageBox.confirm("Confirm Delete", "Are you sure you want to delete " + smni.getName(), new Listener<MessageBoxEvent>() {

						@Override
						public void handleEvent(final MessageBoxEvent be) {
							if (be.getButtonClicked().getItemId().equals(Dialog.YES)) {
								showProcessingScreen();
								deletable.delete(smni, new DeleteCallbackHandler() {

									@Override
									public void deleteFailed(final String deletionFailureReason) {
										MessageBox.alert("Delete Failed", deletionFailureReason, null);
										removeProcessingScreen();
									}

									@Override
									public void deleted() {
										currentPluginIsDirty = false;
										treeStore.remove(smnm);
										removeProcessingScreen();
									}
								});
							}
						}
					});

				}
			});
			contextMenu.add(mi);
		}
		if (plugin instanceof Addable && ((Addable) plugin).canAdd(smni)) {
			final Addable a = (Addable) plugin;
			final MenuItem addMI = new MenuItem("Add " + a.getAddName());
			addMI.setIconStyle(a.getAddIconStyle());
			addMI.addListener(Events.Select, new Listener<MenuEvent>() {

				@Override
				public void handleEvent(@SuppressWarnings("unused") final MenuEvent me) {
					final MessageBox prompt = MessageBox.prompt("Add " + a.getAddName(), "Enter " + a.getAddName() + " name:");
					prompt.addCallback(new Listener<MessageBoxEvent>() {

						@Override
						public void handleEvent(final MessageBoxEvent be) {
							if (be.getButtonClicked().getItemId().equals(Dialog.OK)) {
								showProcessingScreen();
								a.add(be.getValue().trim(), smni, new AddCallbackHandler() {

									@Override
									public void added(final SecurityManagerNavItem smni) {
										if (smni != null) {
											addNavModelToParent(smni, smnm);
										}
										removeProcessingScreen();
									}

									@Override
									public void addedDontClear(final SecurityManagerNavItem smni) {
										if (smni != null) {
											addNavModelToParent(smni, smnm);
										}
									}

									@Override
									public void addCancelled() {
										removeProcessingScreen();
									}

									@Override
									public void addFailed(final String failureReason) {
										MessageBox.alert("Add Failed", failureReason, null);
										removeProcessingScreen();
									}
								});
							}
						}
					});
					prompt.getTextBox().addKeyListener(new KeyListener() {

						@Override
						public void componentKeyUp(final ComponentEvent event) {
							if (ClientConstants.EXTJS_KEY_VALUE_ENTER == event.getKeyCode()) {
								prompt.getDialog().getButtonBar().getItem(0).fireEvent(Events.Select);
							}
						}
					});
				}
			});
			contextMenu.add(addMI);
		}
		if (plugin instanceof CustomAdminActionItemable) {
			for (final CustomAdminActionItem caai : ((CustomAdminActionItemable) plugin).getCustomAdminActionItems(smni)) {
				final MenuItem mi = new MenuItem(caai.getName());
				mi.setIconStyle(caai.getIconStyle());
				mi.addSelectionListener(new SelectionListener<MenuEvent>() {

					@Override
					public void componentSelected(@SuppressWarnings("unused") MenuEvent ce) {
						showProcessingScreen();
						caai.getCustomAdminActionHandler().clicked(new ActionCompleteHandler() {

							@Override
							public void completed() {
								removeProcessingScreen();
							}

							@Override
							public void failed(String string) {
								// MessageBox.alert("Action Failed", string, null);
								MessageBox.alert("Perceptive Licensing Action", string, null);
								removeProcessingScreen();
							}
						});
					}
				});
				mi.setEnabled(caai.getEnabled());
				contextMenu.add(mi);
			}
		}
		if (contextMenu.getItemCount() == 0) {
			getSecurityManagerTree().setContextMenu(null);
		}
		else {
			getSecurityManagerTree().setContextMenu(contextMenu);
		}
	}

	private void actuallyHandleSelectionChange() {
		clearMainPanel();
		if (getSecurityManagerTree().getSelectionModel().getSelectedItem() == null) {
			return;
		}
		showProcessingScreen();
		currentlySelectedModel = getSecurityManagerTree().getSelectionModel().getSelectedItem();
		setupContextMenu();
		currentlySelectedModel.getSecurityManagerPlugin().callItemSelected(currentlySelectedModel.getSecurityManagerNavItem(),
				new ItemSelectedCallbackHandler() {

					@Override
					public void doneRendering() {
						pluginNotDirty();
						// mainSecurityManagerPanel.setSaveDiscardButtonsVisible(currentlySelectedModel.getSecurityManagerPlugin()
						// instanceof Saveable);
						mainSecurityManagerPanel.setBreadcrumbs(currentlySelectedModel, treeStore);
						mainSecurityManagerPanel.setCurrentComposite(currentlySelectedModel.getSecurityManagerPlugin().getView(),
								currentlySelectedModel.getSecurityManagerPlugin() instanceof Saveable);
						removeProcessingScreen();
					}
				});

	}

	private SecurityManagerNavModel getModelForItem(final SecurityManagerNavItem navItem) throws ModelNotFoundException {
		for (final SecurityManagerNavModel smnm : treeStore.getAllItems()) {
			if (smnm.getSecurityManagerNavItem() == navItem) {
				return smnm;
			}
		}
		throw new ModelNotFoundException("No model found for nav item: " + navItem.getName() + "(" + navItem.getClass().getName() + ")");
	}

	// public void promptIfDirtyThenLogoff(final LogoffReturnHandler lrh, final boolean isTimeout)
	// {
	// if (currentlySelectedModel != null && currentPluginIsDirty)
	// {
	// ClientUtils.yesNoCancelMessageBox("Unsaved Changes", "You have unsaved changes; save now?", new Listener<MessageBoxEvent>() {
	//
	// @Override
	// public void handleEvent(final MessageBoxEvent be)
	// {
	// if (be.getButtonClicked().getItemId().equals(Dialog.YES))
	// {
	// ((Saveable) currentlySelectedModel.getSecurityManagerPlugin()).save(new SaveCallbackHandler() {
	//
	// @Override
	// public void saveFailed()
	// {
	// MessageBox.alert("Save Changes", "Changes cannot be saved.", null);
	// }
	//
	// @Override
	// public void saved()
	// {
	// nts.actuallyLogoff(lrh, isTimeout);
	// }
	// });
	// }
	// else if (be.getButtonClicked().getItemId().equals(Dialog.NO))
	// {
	// nts.actuallyLogoff(lrh, isTimeout);
	// }
	// else
	// {
	// // Cancel - do nothing
	// }
	// }
	// });
	// }
	// else
	// {
	// nts.actuallyLogoff(lrh, isTimeout);
	// }
	// }
}
